Skip to content

Codex Code Review 实战:让 AI 帮你找 Bug、并发和数据一致性问题

前面几篇我们已经建立了一套比较完整的 Codex 工作方式:

text
Read

Understand

Plan

Implement

Test

代码写完、测试通过以后,是不是就结束了?

还没有。

真实的软件开发通常还有非常重要的一步:

text
Code Review

过去 Code Review 主要依赖:

text
开发者自己检查
+
同事 Review

现在使用 Codex 以后,可以在正式提交之前增加一层:

text
AI Review

于是流程变成:

text
Implement

Test

Codex Review

Developer Review

Commit / PR

Codex 非常适合做第一轮代码审查,因为它可以:

text
读取 Git Diff
搜索相关代码
追踪调用链
检查上下文
分析边界条件
寻找潜在 Bug

但 Code Review 也不是简单输入一句:

text
帮我看看代码有没有问题

就结束了。

如果 Review Prompt 太模糊,Codex 很容易:

text
只检查代码风格
输出一些无关建议
为了找问题而找问题
忽略真正高风险的业务逻辑

这一篇就专门讲:

如何让 Codex 真正参与 Code Review,而不是只做一次表面的代码点评。


1. 为什么测试通过以后还需要 Review?

因为:

text
测试通过

代码一定正确

测试只能证明:

text
已经覆盖到的场景

没有出现问题。

但真实代码还可能存在:

text
未覆盖的边界条件
并发问题
事务问题
幂等问题
性能问题
安全问题
兼容性问题
可维护性问题

例如:

java
if (balance.compareTo(amount) >= 0) {
    balance = balance.subtract(amount);
    updateBalance(balance);
}

单线程测试可能全部通过。

但是两个请求同时进入:

text
Request A
读取 balance = 100

Request B
读取 balance = 100

两边都认为:

text
余额足够

于是可能产生:

text
并发一致性问题

普通功能测试未必能够发现。

而 Review 可以从:

text
代码结构
+
调用关系
+
并发模型

进一步分析。


2. Codex Review 最适合放在哪个阶段?

推荐:

text
需求

Plan

Implement

Test

Review

Developer Review

Commit

为什么不建议代码刚写一半就进行完整 Review?

因为:

text
代码还没完成
Diff 还在变化
测试还没跑

这时候 Review 很容易浪费上下文。

更适合在:

text
功能基本完成
+
相关测试通过

以后进行。


3. Review 的第一步:先看 Git Diff

Codex 做 Review 时,最重要的输入之一就是:

text
Git Diff

开发者平时也会:

bash
git status
git diff

Codex 同样可以基于这些变更理解:

text
这次到底改了什么

例如:

text
修改了 5 个文件

UserBalance.java
UserBalanceService.java
UserBalanceServiceImpl.java
WalletTransactionType.java
UserBalanceServiceTest.java

相比让 Codex:

text
重新 Review 整个 Repository

基于当前 Diff 更容易聚焦:

text
本次变更

4. 为什么 Review 不应该只看 Diff?

只看 Diff 也存在问题。

例如当前修改:

java
userBalanceService.opsBalance(uid, amount);

仅仅看这一行,很难判断:

text
opsBalance 内部是否有事务?
是否幂等?
是否允许 amount 为负?
是否记录流水?

所以真正有效的 Review 应该是:

text
Git Diff
   +
Relevant Context

也就是:

text
先看变更
再读取相关上下文

可以直接告诉 Codex:

text
Review 当前 Git Diff。

必要时读取相关调用方、被调用方法、Entity、Mapper 和测试,
不要只根据 Diff 表面判断。

5. 不推荐:帮我 Review 一下

例如:

text
帮我 Review 当前代码。

问题和之前的:

text
帮我优化一下

很类似。

Codex 不知道你最关心:

text
代码风格?
Bug?
性能?
事务?
安全?
兼容性?

结果很可能输出:

text
这个方法可以拆分
变量名可以更清晰
建议增加注释

这些不是完全没价值。

但如果这是一个:

text
钱包扣款

需求,真正应该优先关注的可能是:

text
重复扣款
超额扣款
并发
事务
幂等

所以 Review 也需要:

text
明确目标

6. 一个通用的 Review Prompt

可以直接使用:

text
Review 当前 Git Diff。

不要修改代码。

必要时读取相关上下文,
不要只检查 Diff 表面。

重点检查:

1. 明确的逻辑 Bug
2. 空指针
3. 边界条件
4. 异常处理
5. 并发问题
6. 事务问题
7. 幂等问题
8. 数据一致性
9. 性能问题
10. 向后兼容
11. 安全问题
12. 测试遗漏

对于每个问题输出:

- 严重程度
- 文件
- 代码位置
- 问题原因
- 触发条件
- 可能后果
- 建议修复方式

只报告有明确依据的问题。

如果无法确认,
标记为“需要确认”,不要当成确定 Bug。

不要为了输出内容而猜测问题。

最后几句话非常重要。


7. 为什么要告诉 Codex“不要为了 Review 而找问题”?

AI 做 Review 时可能存在一个倾向:

text
用户让我找问题

那我最好输出几个问题

于是可能出现:

text
理论上可以优化
可能存在风险
建议考虑……

但这些问题:

text
不一定真实

所以应该明确:

text
没有问题也可以说没有发现明确问题。

例如:

text
只报告能够从代码中得到明确证据的问题。

如果只是风格偏好,
不要作为 Bug 输出。

这会明显提高 Review 结果的信噪比。


8. Review 结果最好按严重程度分级

不是所有问题都一样重要。

例如:

text
变量名不够清晰

和:

text
可能导致用户重复扣款

显然不是一个级别。

可以让 Codex 使用:

text
P0
P1
P2
P3

例如:

text
P0
→ 严重数据 / 资金 / 安全事故

P1
→ 高概率生产 Bug

P2
→ 边界条件 / 性能 / 维护风险

P3
→ 低风险改进

或者:

text
Critical
High
Medium
Low

重点不是具体名称。

而是:

text
让开发者快速知道先看什么

9. 一个推荐的严重程度定义

可以直接写进 Prompt:

text
严重程度:

P0:
可能导致资金错误、数据损坏、严重安全问题。

P1:
可能导致主要业务错误、重复执行、事务不一致。

P2:
边界条件 Bug、明显性能问题、异常处理问题。

P3:
低风险维护性问题。

不要把纯代码风格问题标记为 P0/P1。

这样 Review 结果会更容易处理。


10. Java Review:空指针

Java 项目中非常常见。

例如:

java
User user = userMapper.selectById(uid);

return user.getName();

如果:

text
user 不存在

就会:

text
NullPointerException

Review 时可以让 Codex 重点检查:

text
Mapper 查询结果
Map.get
List.get
Optional
外部 API 返回值
JSON 字段
数据库 nullable 字段

Prompt:

text
重点检查所有新代码中的 null 假设。

特别关注:

- Mapper 查询可能返回 null
- Map.get
- 外部接口返回值
- nullable 数据库字段
- List 为空

11. Java Review:BigDecimal

资金项目中非常重要。

常见错误:

java
if (amount.doubleValue() > 0) {
}

或者:

java
new BigDecimal(0.1)

或者:

java
amount.equals(new BigDecimal("1.00"))

可能存在:

text
精度
scale
比较行为

问题。

Review 可以明确:

text
检查所有金额处理:

1. 是否使用 BigDecimal
2. 是否使用 double / float
3. compareTo 是否正确
4. 除法是否指定 scale 和 rounding
5. 是否可能产生负余额
6. 金额单位是否一致

对于:

text
支付
钱包
奖励
结算

这应该是固定检查项。


12. Java Review:事务

Spring 项目另一个重点:

text
@Transactional

例如:

text
创建提现订单

扣减余额

如果:

text
订单创建成功
余额扣减失败

应该怎么办?

或者反过来:

text
余额扣了
订单没创建

就可能出现:

text
数据不一致

Review 时应该检查:

text
事务边界
事务传播
异常是否触发回滚
自调用
异步方法
跨服务调用

13. 一个事务 Review Prompt

例如:

text
重点 Review 当前修改中的事务一致性。

请检查:

1. 哪些方法有 @Transactional
2. 事务边界是否覆盖完整业务操作
3. 是否存在 Spring 自调用导致事务失效
4. 是否捕获异常以后没有重新抛出
5. 是否存在 checked exception 不回滚
6. 是否在事务中执行耗时 RPC
7. 是否存在数据库成功但 MQ / RPC 失败
8. 是否存在余额变化与流水不一致

只报告能够结合实际代码说明的问题。

这比:

text
看看事务有没有问题

更有效。


14. Java Review:并发

并发 Bug 是 AI Review 很值得尝试的领域之一。

例如:

text
读取余额

判断余额

扣减余额

在单线程中完全正常。

但两个线程:

text
Thread A
Read 100

Thread B
Read 100

Thread A
-80

Thread B
-80

就可能出现问题。

所以 Review 时可以重点搜索:

text
read-modify-write

模式。

例如:

text
查询

Java 判断

更新

然后分析:

text
是否存在锁
乐观锁
CAS
条件 UPDATE
数据库事务
唯一约束

15. 并发 Review 模板

text
重点 Review 当前修改中的并发安全。

检查:

1. 是否存在 read-modify-write
2. 两个请求同时执行会发生什么
3. 是否依赖先查后改
4. 是否存在乐观锁
5. 是否存在数据库条件更新
6. 是否存在唯一约束
7. Redis 锁是否可能过期
8. 锁粒度是否正确
9. 是否存在重复执行
10. 是否可能产生负余额

对于每个并发问题,
给出一个具体的双请求执行时序。

最后一句特别有用。

不要只让 Codex 说:

text
可能存在并发问题

而是要求它:

text
给出执行时序

16. 什么叫“给出并发执行时序”?

例如:

text
初始余额:100

Request A
→ 查询余额 = 100

Request B
→ 查询余额 = 100

Request A
→ 判断 100 >= 80
→ 成功

Request B
→ 判断 100 >= 80
→ 成功

Request A
→ 更新余额 20

Request B
→ 更新余额 20

最终:

text
系统记录两次扣款
余额却只减少一次

或者根据实现产生:

text
负余额

这种 Review 结果就非常有价值。

因为它给出了:

text
Bug 如何真实发生

17. Review:幂等

涉及:

text
支付回调
充值
提现
MQ
定时任务
第三方通知

都应该重点检查:

text
Idempotency

也就是:

text
同一个业务请求执行两次,
结果是否仍然正确?

例如支付回调:

text
第一次
→ 入账 100

第三方重试
→ 再次回调

第二次
→ 还能不能再入账 100?

如果可以:

text
严重 Bug

18. 幂等 Review 模板

text
重点检查当前修改的幂等性。

对于所有:

- API
- MQ Consumer
- 定时任务
- 支付回调
- 充值确认
- 重试逻辑

分析:

同一个业务请求执行两次会发生什么?

重点检查:

1. 是否存在业务唯一 ID
2. 是否存在数据库唯一约束
3. 是否只在 Java 层判断
4. 判断和写入是否原子
5. 并发重复请求是否仍然安全
6. 失败重试是否可能重复执行副作用

如果发现问题,
给出重复执行的具体路径。

19. Review:数据库唯一约束

很多代码看起来有幂等判断:

java
if (!exists(sourceId)) {
    insert(record);
}

但并发情况下:

text
Request A
exists = false

Request B
exists = false

A insert

B insert

如果数据库没有:

text
UNIQUE

仍然可能重复。

所以涉及业务唯一性的 Review,要同时检查:

text
Java 判断
+
数据库约束

而不是只看 Service。


20. Review:MQ 重复消费

MQ Consumer 通常必须考虑:

text
消息重复

例如:

java
@RabbitListener
public void handle(OrderPaidEvent event) {
    rewardService.reward(event.getUid(), event.getAmount());
}

Review 应该继续问:

text
MQ 重投以后怎么办?

Consumer 崩溃重启怎么办?

业务执行成功但 ACK 失败怎么办?

reward 是否幂等?

所以对于 MQ 代码:

text
消费成功

不是唯一关注点。

还应该看:

text
重复消费
失败重试
ACK
死信
副作用

21. Review:SQL 性能

Code Review 也可以检查性能。

例如:

java
for (Long uid : uids) {
    User user = userMapper.selectById(uid);
}

可能产生:

text
N + 1

如果:

text
uids = 1000

就可能执行:

text
1000 次 SQL

Review 时可以要求:

text
检查新增代码是否存在:

1. 循环 SQL
2. N+1
3. 全表查询
4. 无分页大结果集
5. 不必要的 count
6. 缺失索引的查询条件
7. 重复数据库查询

22. Review:Redis

Redis 相关代码可以重点检查:

text
Key
TTL
并发
缓存一致性
序列化
缓存穿透
缓存击穿

例如:

text
数据库更新成功

Redis 删除失败

会不会导致:

text
旧缓存继续存在?

如果是 Redis Lock:

text
锁有没有唯一 owner?
释放锁时是否可能删掉别人的锁?
TTL 是否可能提前过期?
业务执行时间是否超过 TTL?

这些都很适合专项 Review。


23. Review:接口兼容性

一个很容易被忽略的问题是:

text
代码逻辑没 Bug
但是 API 不兼容了

例如:

text
字段改名
字段删除
类型变化
null 行为变化
错误码变化
分页结构变化
枚举值变化

如果还有:

text
旧 App
第三方调用方
其他微服务

就可能直接出问题。

Review Prompt:

text
检查当前 Diff 的向后兼容性。

重点检查:

1. API 字段删除
2. 字段改名
3. 字段类型变化
4. null 行为变化
5. 枚举变化
6. 错误码变化
7. 默认值变化
8. 数据库字段兼容
9. 旧调用方是否仍然可用

24. Review:异常处理

常见问题:

java
try {
    doSomething();
} catch (Exception e) {
    log.error("error", e);
}

异常被:

text
吃掉

以后,调用方可能认为:

text
执行成功

特别是事务方法中:

text
catch

不抛出

可能导致事务行为和预期不同。

Review 可以检查:

text
异常是否被吞
错误码是否正确
是否错误重试
是否重复记录日志
是否暴露敏感信息

25. Review:测试是否真的有效

有测试不代表测试有价值。

例如:

java
@Test
void testFreeze() {
    assertTrue(true);
}

当然没意义。

更现实的问题是:

text
测试只覆盖正常路径

没有覆盖:

text
余额不足
重复请求
并发
null
异常
回滚
边界值

所以 Code Review 也应该 Review:

text
Test Diff

例如:

text
检查新增测试是否真正覆盖本次修改风险。

重点关注:

1. 正常路径
2. 边界值
3. 异常路径
4. 重复执行
5. 并发
6. 事务回滚
7. 历史数据兼容

指出当前修改中重要但没有测试覆盖的场景。

26. 不要让 Codex 自动修改所有 Review 问题

这是一个很重要的习惯。

第一次 Review 推荐:

text
只输出问题
不要修改代码

为什么?

因为 Review 阶段的目标是:

text
发现问题

如果一边 Review:

text
一边自动修改

就会导致:

text
原始 Diff

Review

产生新 Diff

新的代码又没有 Review

流程会变得混乱。

更好的方式:

text
Review

问题列表

Developer 判断

选择问题

Fix

Test

Review Again

27. Review 发现问题以后怎么修?

例如 Codex 输出:

text
P1

UserBalanceServiceImpl.java

freeze() 存在并发超额冻结风险。

不要直接:

text
全部修复。

可以:

text
修复 Review 中的 P1-1。

要求:

1. 使用项目现有乐观锁机制
2. 不新增 Redis 锁
3. 不修改 API
4. 增加并发测试

完成后运行相关测试。

不要处理其他 Review 项。

这样修改范围更可控。


28. 修复以后再 Review 一次

完整闭环应该是:

text
Review

Find Issue

Fix

Test

Review Again

因为:

text
修 Bug

本身也可能:

text
产生新 Bug

尤其涉及:

text
并发
事务
数据库

最好重新检查。


29. 一个资金业务专项 Review 模板

如果项目涉及:

text
钱包
支付
充值
提现
奖励
结算

可以直接保存下面这套:

text
Review 当前 Git Diff。

不要修改代码。

这是资金相关代码,
优先检查正确性和数据一致性,
不要优先讨论代码风格。

重点检查:

1. 重复入账
2. 重复扣款
3. 超额扣款
4. 负余额
5. BigDecimal 精度
6. 事务边界
7. 异常回滚
8. 并发 read-modify-write
9. 幂等
10. 数据库唯一约束
11. MQ 重复消费
12. 定时任务重复执行
13. 流水和余额是否一致
14. sourceId / businessId 去重
15. API 向后兼容

必要时读取:

- Service
- Mapper
- Entity
- SQL
- 调用方
- 测试

每个问题输出:

严重程度:
文件:
位置:
问题:
触发路径:
后果:
证据:
建议:

只报告有实际代码依据的问题。

无法确认时明确标记“需要确认”。

不要为了输出 Review 内容而猜测问题。

30. 一个普通 Java 项目的 Review 模板

如果不是资金系统,可以使用更通用的版本:

text
Review 当前 Git Diff。

不要修改代码。

重点检查:

1. 逻辑正确性
2. null
3. 边界条件
4. 异常处理
5. 资源释放
6. 事务
7. 并发
8. 性能
9. SQL
10. 安全
11. API 兼容
12. 测试覆盖

必要时读取相关上下文。

只报告明确、可操作的问题。

不要输出纯个人代码风格偏好。

按照 P0 / P1 / P2 / P3 排序。

31. Review 可以拆成多轮

对于大型 Diff,一次 Review 所有问题可能效果并不好。

例如:

text
50 个文件
3000 行修改

可以拆成:

text
第一轮
→ Correctness

第二轮
→ Concurrency & Transaction

第三轮
→ Performance

第四轮
→ Compatibility

第五轮
→ Tests

例如第一轮:

text
只检查业务正确性。

第二轮:

text
只检查事务、并发和幂等。

这种:

text
专项 Review

通常比:

text
一次检查所有东西

更加深入。


32. 什么情况下值得多轮 Review?

比较适合:

text
大型重构
支付
钱包
认证
数据库迁移
跨模块修改
复杂并发
高风险线上修复

简单需求:

text
修改一个 DTO

就没必要:

text
Review 五轮

仍然应该按照:

text
风险

决定 Review 深度。


33. Codex Review 不能替代人工 Review

这是必须明确的一点。

Codex 可以帮助:

text
扫描 Diff
追踪调用
发现模式
检查边界
寻找潜在风险

但是它并不知道所有:

text
产品规则
历史背景
线上约束
团队决策
隐藏业务需求

例如:

text
一个字段看起来完全没用了

Codex 可能建议删除。

但你知道:

text
旧版 App 仍然依赖

所以最终责任仍然属于:

text
Developer

34. AI Review 最合理的位置是什么?

不是:

text
AI Review
替代
Human Review

而是:

text
Developer

Codex First Review

修复明显问题

Human Review

可以理解成:

text
AI
→ 第一层过滤器

Developer
→ 最终决策者

这样可以减少很多:

text
低级错误
明显遗漏
重复劳动

把人工精力留给:

text
业务
架构
设计
风险判断

35. 推荐的完整 Codex Review 工作流

最终可以固定成:

text
① 完成实现

② 运行测试

③ git status

④ git diff

⑤ Codex Review

⑥ 按严重程度检查问题

⑦ 修复确认的问题

⑧ 再次运行测试

⑨ 再次 Review

⑩ Developer Review

⑪ Commit / PR

如果是高风险代码:

text
普通 Review

事务专项 Review

并发专项 Review

幂等专项 Review

兼容性 Review

36. 最后怎么理解 Codex Code Review?

如果只记一句话:

text
不要让 Codex 只评价代码写得好不好。

要让它寻找:
什么情况下这段代码会出错。

一个好的 Review 不是:

text
建议优化方法命名。

而是能够告诉你:

text
当两个提现请求同时到达时:

A 和 B 都读取 balance = 100

A 判断余额足够
B 也判断余额足够

然后两个请求都执行扣减

当前实现没有乐观锁、
条件 UPDATE 或其他并发保护

因此可能产生重复扣款或余额错误。

这才是真正有价值的:

text
Code Review

最终可以把整个 Codex 开发流程串起来:

text
AGENTS.md

Prompt

Explore

Plan

Implement

Test

Review

Developer Review

其中 Review 解决的是:

text
代码已经写出来以后,
还有哪些问题没有被测试发现?

当 Codex 不再只是:

text
帮你写代码

而开始参与:

text
理解需求
设计方案
实现代码
执行测试
检查 Diff
Code Review

它才真正从一个:

text
AI 代码生成器

变成:

text
参与软件工程全过程的 Coding Agent